package com.vjwealth.android.nos.java.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.vjwealth.android.nos.R;

/**
 * projectName MyApplication
 * date 2017/5/27
 * description com.example.administrator.myapplication
 */

public class CircleMenuView extends View {

    private Context mContext;
    private float mWidth, mHeight;
    private float mCircleRadius;
    private float mCircleMenuRadius;
    //背景
    private RectF mBackgroundRectF;
    private Paint mBackgroundPaint;
    private Bitmap mBackgroundBmp;
    //按钮
    private Bitmap mCenterBtnBmp;
    private float mCenterBtnX, mCenterBtnY;
    private boolean mCenterSelected;

    private double dragEndX;
    private double dragEndY;

    //可触发拖动的范围
    private Rect mCenterRect = new Rect();
    private Region mCenterRegion = new Region();
    //可以拖动的范围
    private float mDragRadius;
    private Rect mDragRect;
    private Region mDragRegion;
    //手指的最大范围(外面圆盘的范围)
    private Rect mMaxDragRect;
    private Region mMaxDragRegion;

    private int selectId = -1;
    private int mUpSelectId = -1;
    private float offsetAngle = 54;
    private static final int childMenuSize = 5;
    private static final float childAngle = 360f / childMenuSize;

    private OnCircleMenuClickListener onCircleMenuClickListener;

    public interface OnCircleMenuClickListener{
        void onClick(int position);
    }


    public CircleMenuView(Context context) {
        this(context, null);
    }

    public CircleMenuView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
    }

    public CircleMenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
        setViewAttributes(context, attrs, defStyleAttr);
        initMovie();
    }

    private void init(Context context){
        mContext = context;
        mBackgroundPaint = new Paint();
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setDither(true);
        mBackgroundPaint.setStyle(Paint.Style.STROKE);
        mBackgroundRectF = new RectF();
        mCenterRect = new Rect();
        mMaxDragRect = new Rect();
        mDragRect = new Rect();
        mBackgroundBmp = BitmapFactory.decodeResource(getResources(), R.drawable.wheel_bg);
        mCenterBtnBmp = BitmapFactory.decodeResource(getResources(), R.drawable.center_btn);
        mCenterBtnX = mCenterBtnY = 0;
        mCenterSelected = false;
        dragEndX = dragEndY = 0;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getWidth();
        mHeight = getHeight();
        mCircleRadius = mWidth/2;
        mCircleMenuRadius = mCircleRadius - 14;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int realWidth = startMeasure(widthMeasureSpec);
        int realHeight = startMeasure(heightMeasureSpec);
        setMeasuredDimension(realWidth, realHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        canvas.translate(mCircleRadius, mCircleRadius); //移动坐标原点到中心
//        drawbackground(canvas);
        drawBackground(canvas);
        drawCenterImage(canvas);
        showMenuGif(canvas);
        drawCenterGif(canvas);
    }

    private void drawbackground(Canvas canvas){
        Rect rect = new Rect((int)-(mCircleRadius), (int)-(mCircleRadius), (int)(mCircleRadius), (int)(mCircleRadius));
        mBackgroundPaint.setColor(ContextCompat.getColor(mContext, R.color.colorTitle));
        canvas.drawRect(rect, mBackgroundPaint);
    }

    private void drawBackground(Canvas canvas){
        mBackgroundRectF.set(-mCircleMenuRadius, -mCircleMenuRadius, mCircleMenuRadius, mCircleMenuRadius);
        mMaxDragRect.set((int)-mCircleMenuRadius, (int)-mCircleMenuRadius, (int)mCircleMenuRadius, (int)mCircleMenuRadius);
        canvas.save();
        canvas.drawBitmap(mBackgroundBmp, null, mBackgroundRectF, mBackgroundPaint);
        mMaxDragRegion = new Region(mMaxDragRect);
        canvas.restore();
    }

    private void drawCenterImage(Canvas canvas){
        float centerOffset = dip2px(mContext, 90);
        float dragOffset = dip2px(mContext, 114);
        mCenterRect.set((int)(-mCircleMenuRadius+centerOffset), (int)(-mCircleMenuRadius+centerOffset),
                (int)(mCircleMenuRadius-centerOffset), (int)(mCircleMenuRadius-centerOffset));

        mDragRadius = mCircleMenuRadius-dragOffset;
        mDragRect.set((int)(-mCircleMenuRadius+dragOffset), (int)(-mCircleMenuRadius+dragOffset),
                (int)(mCircleMenuRadius-dragOffset), (int)(mCircleMenuRadius-dragOffset));
        canvas.save();
        canvas.translate(mCenterBtnX, mCenterBtnY);
        canvas.drawBitmap(mCenterBtnBmp, null, mCenterRect, mBackgroundPaint);
        mCenterRegion = new Region(mCenterRect);
        mDragRegion = new Region(mDragRect);
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                double x = event.getX()-mCircleMenuRadius;
                double y = event.getY()-mCircleMenuRadius;
                if(mCenterRegion.contains((int)x, (int)y)){  //拖动选择按钮
                   mCenterSelected = true;
                }else{  //点击选择按钮
                    selectId = whichSector(x, y, mCircleMenuRadius);
                }
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                mCenterBtnX = (event.getX()-mCircleMenuRadius);
                mCenterBtnY = (event.getY()-mCircleMenuRadius);
                mDragSelected = -2;
                boolean b1 = mCenterSelected;
                boolean b2 = mMaxDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY);
                boolean b3 = mDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY);
                if(mCenterSelected && !mMaxDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY)){
                    mCenterBtnX = mCenterBtnY = 0;
                }else if(mCenterSelected
                        && mMaxDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY)
                        && !mDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY)){
                    //计算获得可拖动的最大圆上的点坐标
                    float[] f = fun(mCenterBtnX, mCenterBtnY);
                    mCenterBtnX = f[0];
                    mCenterBtnY = f[1];
                    //拖动到那个扇区，显示相应的gif
                    mDragSelected = whichSector(mCenterBtnX, mCenterBtnY, mCircleMenuRadius);

                }else if(mCenterSelected
                        && mMaxDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY)
                        && mDragRegion.contains((int)mCenterBtnX, (int)mCenterBtnY)){
                }else{
                    mCenterBtnX = 0;
                    mCenterBtnY = 0;
                }
                dragEndX = mCenterBtnX;
                dragEndY = mCenterBtnY;
                Log.i("CircleMenu_MOVE", "b1 = " + b1 + ", b2 = " + b2 + " ,b3 = " + b3);
                Log.i("CircleMenu", "dragEndX = "+dragEndX+", dragEndY = "+ dragEndY);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                double upX = event.getX()-mCircleMenuRadius;
                double upY = event.getY()-mCircleMenuRadius;
                mUpSelectId = whichSector(upX, upY, mCircleMenuRadius);
                if(mCenterSelected && isDrag(dragEndX, dragEndY)){
                    if(onCircleMenuClickListener != null){
                        onCircleMenuClickListener.onClick(mUpSelectId);
                    }
                }else if(mUpSelectId == selectId){
                    if(onCircleMenuClickListener != null){
                        onCircleMenuClickListener.onClick(mUpSelectId);
                    }
                }
                mDragSelected = -2;
                selectId = -1;
                dragEndX = dragEndY = 0;
                mCenterBtnX = 0;
                mCenterBtnY = 0;
                mCenterSelected = false;
                invalidate();
                break;
        }
        return true;
    }

    public void setOnCircleMenuClickListener(OnCircleMenuClickListener listener) {
        this.onCircleMenuClickListener = listener;
    }

    private boolean isDrag(double endX, double endY){
        if(dragEndX != 0 && dragEndY != 0) {
            double _x = Math.abs(0 - endX);
            double _y = Math.abs(0 - endY);
            double distance = Math.sqrt(_x * _x + _y * _y);
            Log.i("CircleMenu_distance", "distance = " + distance);
            return distance >= 37.99;
        }
        return false;

    }

    /**
     * View 被拖动到最大区域外后，x,y 坐标转换为可被拖动的最大坐标值
     * @param x x坐标
     * @param y y坐标
     * @return 处理后的坐标
     */
    private float[] fun(float x, float y){
        double arg = Math.round(Math.atan2(y, x) / Math.PI * 180);//求复数的辐角。
        arg = arg < 0? arg+360:arg;
        float tempX = (float) (Math.cos(arg * Math.PI / 180) * mDragRadius);
        float tempY = (float) (Math.sin(arg * Math.PI / 180) * mDragRadius);
        float[] f = new float[2];
        f[0] = tempX;
        f[1] = tempY;
        return f;
    }

    /**
     * 计算点在那个扇形区域
     * @param X
     * @param Y
     * @param R 半径
     * @return
     */
    private int whichSector(double X, double Y, double R) {
        double mod;
        mod = Math.sqrt(X * X + Y * Y); //将点(X,Y)视为复平面上的点，与复数一一对应，现求复数的模。
        double offset_angle;
        double arg;
        arg = Math.round(Math.atan2(Y, X) / Math.PI * 180);//求复数的辐角。
        arg = arg < 0? arg+360:arg;
        if(offsetAngle%360 < 0){
            offset_angle = 360+offsetAngle%360;
        }else{
            offset_angle = offsetAngle%360;
        }
        if (mod > R) { //如果复数的模大于预设的半径，则返回0。
            return -2;
        } else { //根据复数的辐角来判别该点落在那个扇区。
            for(int i=0;i<childMenuSize;i++){
                if(isSelect(arg, i,offset_angle) || isSelect(360+arg, i,offset_angle)){
                    return i;
                }
            }
        }
        return -1;
    }
    /**
     * 判读该区域是否被选中
     * @param arg 角度
     * @param i
     * @param offsetAngle 偏移角度
     * @return 是否被选中
     */
    private boolean isSelect(double arg, int i, double offsetAngle) {
        boolean b = arg>(i*childAngle+offsetAngle%360) && arg<((i+1)*childAngle+offsetAngle%360);
        Log.i("CircleMenu_Select", "arg = "+arg+",i = "+i +", a = "+b);
        return b;
    }


    private int startMeasure(int msSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(msSpec);
        int size = MeasureSpec.getSize(msSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = dip2px(mContext,200);
        }
        return result;
    }

    /**
     * 将dip或dp值转换为px值，保证尺寸大小不变
     * @param dipValue（DisplayMetrics类中属性density）
     * @return
     */
    public int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }


    /**
     * 播放中心的gif
     */
    ////////////////////////////////////////////////////////////////////////////////////////////////
    private volatile boolean mPaused = false;

    private int mMovieResourceId = -1;
    private Movie mMovie;  //显示gif 动画
    private long mMovieStart;
    private int mCurrentAnimationTime = 0;
    private boolean mVisible = true;
    /**
     * 默认为1秒
     */
    private static final int DEFAULT_MOVIE_DURATION = 1000;
    /**
     * 绘制gif
     **/
    @SuppressLint("NewApi")
    private void setViewAttributes(Context context, AttributeSet attrs, int defStyle) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        // 从描述文件中读出gif的值，创建出Movie实例
        final TypedArray array = context.obtainStyledAttributes(attrs,
                R.styleable.GifView, defStyle, R.style.AppTheme);
        mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
        mPaused = array.getBoolean(R.styleable.GifView_paused, false);
        array.recycle();
        if (mMovieResourceId != -1) {
            mMovie = Movie.decodeStream(getResources().openRawResource(
                    mMovieResourceId));
        }
    }
    /**
     * 设置gif图资源
     */
    public void setMovieResource(int movieResId) {
        this.mMovieResourceId = movieResId;
        mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
        requestLayout();
    }
    public void setMovie(Movie movie) {
        this.mMovie = movie;
        requestLayout();
    }
    public Movie getMovie() {
        return mMovie;
    }
    public void setMovieTime(int time) {
        mCurrentAnimationTime = time;
        invalidate();
    }
    /**
     * 设置暂停
     */
    public void setPaused(boolean paused) {
        this.mPaused = paused;
        if (!paused) {
            mMovieStart = android.os.SystemClock.uptimeMillis()
                    - mCurrentAnimationTime;
        }
        invalidate();
    }
    /**
     * 判断gif图是否停止了
     */
    public boolean isPaused() {
        return this.mPaused;
    }

    private void drawCenterGif(Canvas canvas){
        if (mMovie != null) {
            if (!mPaused) {
                updateAnimationTime();
                drawMovieFrame(canvas);
                invalidateView();
            } else {
                drawMovieFrame(canvas);
            }
        }
    }

    @SuppressLint("NewApi")
    private void invalidateView() {
        if (mVisible) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                postInvalidateOnAnimation();
            } else {
                invalidate();
            }
        }
    }
    private void updateAnimationTime() {
        long now = android.os.SystemClock.uptimeMillis();
        // 如果第一帧，记录起始时间
        if (mMovieStart == 0) {
            mMovieStart = now;
        }
        // 取出动画的时长
        int dur = mMovie.duration();
        if (dur == 0) {
            dur = DEFAULT_MOVIE_DURATION;
        }
        // 算出需要显示第几帧
        mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
    }
    private void drawMovieFrame(Canvas canvas) {
        // 设置要显示的帧，绘制即可
        mMovie.setTime(mCurrentAnimationTime);
        canvas.save();
        canvas.translate(mCenterBtnX, mCenterBtnY);
        int h = mMovie.height();
        int w = mMovie.width();
        float scale = mCenterRect.height() / (float)h;   //缩放画布 控制gif的显示大小
        canvas.scale(scale, scale);
        mMovie.draw(canvas, -h/2, -w/2);
        canvas.restore();
    }
    @SuppressLint("NewApi")
    @Override
    public void onScreenStateChanged(int screenState) {
        super.onScreenStateChanged(screenState);
        mVisible = screenState == SCREEN_STATE_ON;
        invalidateView();
    }
    @SuppressLint("NewApi")
    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        mVisible = visibility == View.VISIBLE;
        invalidateView();
    }
    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        mVisible = visibility == View.VISIBLE;
        invalidateView();
    }

    /**
     * 播放 选中的Menu动画
     **/
    ////////////////////////////////////////////////////////////////////////////////////////////////
    private Movie mMenuMovie;  //显示gif 动画
    private long mMenuMovieStart;
    private int mMenuCurrentAnimationTime = 0;
    private int mDragSelected = -2;
    private Movie mBackMovie, mRescueMovie, mMyNOSMovie, mSubscribeMovie, mCatalogMovie;

    private void initMovie(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                mBackMovie = Movie.decodeStream(getResources().openRawResource(R.raw.trggel_back));
                mRescueMovie = Movie.decodeStream(getResources().openRawResource(R.raw.rescue_service));
                mMyNOSMovie = Movie.decodeStream(getResources().openRawResource(R.raw.my_nos_home));
                mSubscribeMovie = Movie.decodeStream(getResources().openRawResource(R.raw.my_reserve_home));
                mCatalogMovie = Movie.decodeStream(getResources().openRawResource(R.raw.love_record));
            }
        }).start();
    }

    private void showMenuGif(Canvas canvas){
        if(mDragSelected == -2){
            return;
        }else if(mDragSelected == 0){
            mMenuMovie = mBackMovie;
        }else if(mDragSelected == 1){
            mMenuMovie = mCatalogMovie;
        }else if(mDragSelected == 2){
            mMenuMovie = mSubscribeMovie;
        }else if(mDragSelected == 3){
            mMenuMovie = mMyNOSMovie;
        }else if(mDragSelected == 4){
            mMenuMovie = mRescueMovie;
        }
        if (mMenuMovie != null) {
            updateMenuAnimationTime();
            drawMenuMovieFrame(canvas);
            invalidateView();
        }
    }

    private void updateMenuAnimationTime() {
        long now = android.os.SystemClock.uptimeMillis();
        // 如果第一帧，记录起始时间
        if (mMenuMovieStart == 0) {
            mMenuMovieStart = now;
        }
        // 取出动画的时长
        int dur = mMenuMovie.duration();
        if (dur == 0) {
            dur = DEFAULT_MOVIE_DURATION;
        }
        // 算出需要显示第几帧
        mMenuCurrentAnimationTime = (int) ((now - mMenuMovieStart) % dur);
    }
    private void drawMenuMovieFrame(Canvas canvas) {
        // 设置要显示的帧，绘制即可
        mMenuMovie.setTime(mMenuCurrentAnimationTime);
        canvas.save();
        int h = mMenuMovie.height();
        int w = mMenuMovie.width();
        float scale = mWidth / w;
        canvas.scale(scale, scale);
        mMenuMovie.draw(canvas, -h/2, -w/2);
        canvas.restore();
    }
}
